/**
 * 该文件用于对 axios 做统一封装
 */

import axios from "axios";
import { ElMessage } from "element-plus";
import { getToken } from "./auth";
import storage from "./storage";
import store from "@/store";
import router from "@/router";
import { refreshToken } from "@/api/login";
// console.log("ENV", import.meta.env);
// console.log("MODE", import.meta.env.MODE);

// 创建 axios 实例
const request = axios.create({
  // 基础接口前缀地址
  //    特点：
  //        请求时不以协议开头，则会拼接该地址
  //    好处：
  //        1. 统一配置，减少后续劳动
  baseURL: import.meta.env.VITE_API_BASEURL,
  // import.meta.env.MODE === "development"
  //   ? "http://127.0.0.1:8001"
  //   : import.meta.env.MODE === "stg"
  //   ? "https://stg.com"
  //   : import.meta.env.MODE === "uat"
  //   ? "https://uat.com"
  //   : "https://www.baidu.com",

  // 超时时间，单位为毫秒
  timeout: 1000 * 10,

  // 请求头
  headers: {
    x: 10,
    y: 20,
    // Token 的携带不能直接在这里操作，应该该数据会发生变化（登录前后）
    // Authorization: getToken(),
  },
});

// 用于存储请求的队列
let quequ = [];
// 用于表示当前是否在刷新TOKEN中
let isRefreshing = false;

// 请求拦截器
//    1. 请求发出之前对请求配置做一些处理
request.interceptors.request.use(
  /**
   *
   * @param {*} config - 请求配置
   * @returns 将 config 返回出去，让请求发出
   */
  (config) => {
    // 获取 token
    const token = storage.get("token");

    if (token) {
      config.headers.Authorization = token;

      // 如果是刷新TOKEN的接口就不需要判断 TOKEN 是否过期
      if (config.url.includes("refreshToken")) {
        console.log("当前是刷新TOKEN的接口调用");
        return config;
      }

      // 判断 token 是否过期
      if (storage.isExpired("token")) {
        if (storage.isExpired("refreshToken")) {
          // refreshToken 过期了 。 让请求直接返回，在响应拦截器中有处理重新登录
          return config;
        }

        console.log("token 过期了");

        if (!isRefreshing) {
          isRefreshing = true;

          // 调用刷新TOKEN的接口
          refreshToken(storage.get("refreshToken")).then((result) => {
            // 刷新TOKEN完成
            //  1. 将本地的 TOKEN 给修改掉
            storage.set("token", result.token, result.expire);
            //  2. 刷新TOKEN 要不要替换掉  不要
            //  3. 将之前的请求发出
            quequ.forEach((cb) => {
              cb(result.token);
            });
            //  4. 清空队列
            quequ = [];
            //  5. 将 isRefreshing 重置
            isRefreshing = false;

            console.log("刷新TOKEN接口的返回值", result);
          });
        }

        // 返回一个新的 Promise，阻止当前请求发出
        return new Promise((resolve) => {
          // resolve()
          // 将当前的请求追加到队列中
          quequ.push((newToken) => {
            console.log("之前的请求config", config);
            // 修改之前的请求中的 token
            config.headers.Authorization = newToken;
            resolve(config);
          });
        });
      }
    }

    return config;
  }
);

// 响应拦截器
//    1. 请求响应回来到 .then 的回调函数执行之前做一些处理
request.interceptors.response.use(
  /**
   * http状态码为 2xx、304 时触发
   * @param {*} response - axios Response 对象
   * @returns
   */
  (response) => {
    // console.log("响应1", response);
    // 获取接口返回数据
    const result = response.data;
    // 判断业务状态码是否成功
    if (result.code !== 1000) {
      // 失败
      ElMessage.error(result.message || "网络异常，请稍后重试！！！");
      return Promise.reject(result);
    }

    // 业务成功
    return result.data;
  },
  /**
   * http状态码非 2xx 时触发
   * @param {*} error - axios Error 对象
   * @returns
   */
  (error) => {
    console.log("响应2", error);

    if (error.response) {
      // 取出 http 状态码
      const { status } = error.response;
      // 根据不同的状态码做不同业务逻辑
      switch (status) {
        case 401:
          // token过期
          ElMessage.error("登录失效，请重新登录");
          // 重置路由器
          router.reset();
          // 清理store
          store.commit("user/clear");
          // 回到登录页面
          router.replace("/login");
          return;

        default:
          break;
      }
    }

    return Promise.reject(error);
  }
);

export default request;
